From 2a91f00708bc947915d54351b57772044e2e9397 Mon Sep 17 00:00:00 2001 From: "mafetter@fleming.research" Date: Thu, 25 Nov 2004 10:38:14 +0000 Subject: [PATCH] bitkeeper revision 1.1159.192.1 (41a5b616PKr3oSl-gLQrEOCfYSXbTw) Don't flip a segment unless it will actually help fix the problem. Also made the insn decoder slightly more real. Bug fix in detecting expand-down segments. --- xen/arch/x86/x86_32/mm.c | 2 +- xen/arch/x86/x86_32/seg_fixup.c | 53 ++++++++++++++++++++------------- xen/include/asm-x86/desc.h | 5 +++- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/xen/arch/x86/x86_32/mm.c b/xen/arch/x86/x86_32/mm.c index d90a60c520..ed95ca77e9 100644 --- a/xen/arch/x86/x86_32/mm.c +++ b/xen/arch/x86/x86_32/mm.c @@ -191,7 +191,7 @@ int check_descriptor(unsigned long *d) if ( (b & _SEGMENT_G) ) limit <<= 12; - if ( (b & (3<<10)) == 1 ) + if ( (b & (_SEGMENT_CODE | _SEGMENT_EC)) == _SEGMENT_EC ) { /* * Grows-down limit check. diff --git a/xen/arch/x86/x86_32/seg_fixup.c b/xen/arch/x86/x86_32/seg_fixup.c index 85d7d75def..a102508c83 100644 --- a/xen/arch/x86/x86_32/seg_fixup.c +++ b/xen/arch/x86/x86_32/seg_fixup.c @@ -169,7 +169,7 @@ int linearise_address(u16 seg, unsigned long off, unsigned long *linear) return 1; } -int fixup_seg(u16 seg, int positive_access) +int fixup_seg(u16 seg, unsigned long offset) { struct domain *d = current; unsigned long *table, a, b, base, limit; @@ -208,7 +208,7 @@ int fixup_seg(u16 seg, int positive_access) /* We only parse 32-bit page-granularity non-privileged data segments. */ if ( (b & (_SEGMENT_P|_SEGMENT_S|_SEGMENT_DB| - _SEGMENT_G|(1<<11)|_SEGMENT_DPL)) != + _SEGMENT_G|_SEGMENT_CODE|_SEGMENT_DPL)) != (_SEGMENT_P|_SEGMENT_S|_SEGMENT_DB|_SEGMENT_G|_SEGMENT_DPL) ) { DPRINTK("Bad segment %08lx:%08lx\n", a, b); @@ -219,10 +219,10 @@ int fixup_seg(u16 seg, int positive_access) base = (b&(0xff<<24)) | ((b&0xff)<<16) | (a>>16); limit = (((b & 0xf0000) | (a & 0x0ffff)) + 1) << 12; - if ( b & (1 << 10) ) + if ( b & _SEGMENT_EC ) { /* Expands-down: All the way to zero? Assume 4GB if so. */ - if ( ((base + limit) < PAGE_SIZE) && positive_access ) + if ( ((base + limit) < PAGE_SIZE) && (offset <= limit) ) { /* Flip to expands-up. */ limit = PAGE_OFFSET - base; @@ -231,8 +231,16 @@ int fixup_seg(u16 seg, int positive_access) } else { - /* Expands-up: All the way to Xen space? Assume 4GB if so. */ - if ( ((PAGE_OFFSET - (base + limit)) < PAGE_SIZE) && !positive_access ) + /* + * Expands-up: All the way to Xen space? Assume 4GB if so. + * NB: we compare offset with limit-15, instead of the "real" + * comparison of offset+15 (worst case) with limit, + * to avoid possible unsigned int overflow of offset+15. + * limit-15 will not underflow here because we don't allow expand-up + * segments with maxlimit. + */ + if ( ((PAGE_OFFSET - (base + limit)) < PAGE_SIZE) && + ((offset) > (limit-15)) ) { /* Flip to expands-down. */ limit = -(base & PAGE_MASK); @@ -250,7 +258,7 @@ int fixup_seg(u16 seg, int positive_access) limit = (limit >> 12) - 1; a &= ~0x0ffff; a |= limit & 0x0ffff; b &= ~0xf0000; b |= limit & 0xf0000; - b ^= 1 << 10; /* grows-up <-> grows-down */ + b ^= _SEGMENT_EC; /* grows-up <-> grows-down */ /* NB. These can't fault. Checked readable above; must also be writable. */ table[2*idx+0] = a; table[2*idx+1] = b; @@ -317,37 +325,40 @@ int gpf_emulate_4gb(struct xen_regs *regs) goto fail; } - if ( (pb - eip) == 4 ) - break; - + if ( (pb - eip) >= 15 ) + { + DPRINTK("Too many instruction prefixes for a legal instruction\n"); + goto fail; + } + switch ( b ) { - case 0xf0: /* LOCK */ - case 0xf2: /* REPNE/REPNZ */ - case 0xf3: /* REP/REPE/REPZ */ case 0x67: /* Address-size override */ DPRINTK("Unhandleable prefix byte %02x\n", b); goto fixme; case 0x66: /* Operand-size override */ - break; + case 0xf0: /* LOCK */ + case 0xf2: /* REPNE/REPNZ */ + case 0xf3: /* REP/REPE/REPZ */ + continue; case 0x2e: /* CS override */ pseg = ®s->cs; - break; + continue; case 0x3e: /* DS override */ pseg = ®s->ds; - break; + continue; case 0x26: /* ES override */ pseg = ®s->es; - break; + continue; case 0x64: /* FS override */ pseg = ®s->fs; - break; + continue; case 0x65: /* GS override */ pseg = ®s->gs; - break; + continue; case 0x36: /* SS override */ pseg = ®s->ss; - break; + continue; default: /* Not a prefix byte */ goto done_prefix; } @@ -455,7 +466,7 @@ int gpf_emulate_4gb(struct xen_regs *regs) offset += *(u32 *)memreg; skip_modrm: - if ( !fixup_seg((u16)(*pseg), (signed long)offset >= 0) ) + if ( !fixup_seg((u16)(*pseg), offset) ) goto fail; /* Success! */ diff --git a/xen/include/asm-x86/desc.h b/xen/include/asm-x86/desc.h index 0e2967c4f8..0d6fc65b32 100644 --- a/xen/include/asm-x86/desc.h +++ b/xen/include/asm-x86/desc.h @@ -27,8 +27,11 @@ (((_s)&3) == 1)) #define VALID_CODESEL(_s) ((_s) == FLAT_RING1_CS || VALID_SEL(_s)) -/* These are bitmasks for the first 32 bits of a descriptor table entry. */ +/* These are bitmasks for the high 32 bits of a descriptor table entry. */ #define _SEGMENT_TYPE (15<< 8) +#define _SEGMENT_EC ( 1<<10) /* Expand-down or Conforming segment */ +#define _SEGMENT_CODE ( 1<<11) /* Code (vs data) segment for non-system + segments */ #define _SEGMENT_S ( 1<<12) /* System descriptor (yes iff S==0) */ #define _SEGMENT_DPL ( 3<<13) /* Descriptor Privilege Level */ #define _SEGMENT_P ( 1<<15) /* Segment Present */ -- 2.30.2